package libra.init;

import javax.annotation.PostConstruct;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.DefaultBlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;


//标注配置类
@Configuration
//开启web配置
@EnableWebMvc
//开启事务配置
@EnableTransactionManagement
//指定包扫描
@ComponentScan("libra")
//读取properties文件
//@PropertySource(value={"classpath:db.properties"},encoding="UTF-8")
// 开启AOP代理自动配置，识别@Aspect切面标识注解
@EnableAspectJAutoProxy
public class Config implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		/****************************
		 * 注册Sentinel的Interceptor *
		 ****************************/
		/*
		 * 创建SentinelWebInterceptor拦截器的config配置
		 * SentinelWebMvcConfig可以设置HttpMethodSpecify、UrlCleaner、BlockExceptionHandler
		 * 	通过setHttpMethodSpecify()设置是否区分请求url的类型；
		 * 	通过setUrlCleaner()设置自定义UrlCleaner；
		 * 	通过setBlockExceptionHandler()设置自定义BlockExceptionHandler；
		 */
		SentinelWebMvcConfig config = new SentinelWebMvcConfig();
		// 所有访问的Web-URL就会被自动统计为Sentinel的资源，可以针对单个URL维度进行流控。
		// 如果希望区分不同的HTTP_Method_Type，可以将HTTP_METHOD_SPECIFY设为true。例如：'/foo' -> 'GET:/foo'
        config.setHttpMethodSpecify(true);
        /*
         * 设置使用自定义BlockExceptionHandler
         * SentinelWebMvcConfig创建时BlockExceptionHandler默认为null。对于流控异常不进行处理，会向上抛出异常
         * 本案例，我们使用Sentinel自带的默认实现的DefaultBlockExceptionHandler进行处理
         */
        config.setBlockExceptionHandler( new DefaultBlockExceptionHandler() );
		/*
		 * 设置使用自定义UrlCleaner
		 * SentinelWebMvcConfig创建时BlockExceptionHandler默认为null。
		 * 但是Sentinel提供的SpringMVC支持sentinel-spring-webmvc-adapter.jar内部是以当前方法的@RequestMapping映射作为资源名
		 * 不会出现像CommonFilter那样，由于REST风格请求参数不同而导致Sentinel定义多个资源的情况
		 */
//        config.setUrlCleaner( null );
        
        registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");
	}


	/**
	 * 结合sentinel-annotation-aspectj依赖
	 * 配合@SentinelResource注解使用，在容器中必须配置该bean对象 
	 */
	@Bean
	public SentinelResourceAspect sentinelResourceAspect() {
		return new SentinelResourceAspect();
	}
	
	@PostConstruct
	public void SentinelInit() {
//		/*
//		 * 自定义UrlCleaner
//		 * 该接口实现的作用是：
//		 * 	1、将REST风格的url进行归类
//		 * 	2、将资源文件进行屏蔽，不计入Sentinel资源
//		 */
//		UrlCleaner urlCleaner = new UrlCleaner() {
//			@Override
//			public String clean(String originUrl) {
//				if (originUrl == null || originUrl.isEmpty()) 
//		            return originUrl;
//
//		        // 比如将满足 /foo/{id} 的 URL 都归到 /foo/*
//		        if (originUrl.startsWith("/foo/")) 
//		            return "/foo/*";
//		        
//		        // 不希望统计 *.jsp 的资源文件，可以将其转换为empty string(since 1.6.3)
//		        if (originUrl.endsWith(".jsp")) 
//		            return "";
//		        return originUrl;
//			}
//		};
//		/*
//		 * 设置使用自定义UrlCleaner
//		 * 	如果屏蔽该行代码，Sentinel会使用自带的DefaultUrlCleaner。
//		 * 	对访问的url不做处理，直接进行返回。会续操作会对该接口的返回进行Sentinel的资源定义。
//		 */
//		WebCallbackManager.setUrlCleaner( urlCleaner );
	}
	
	//静态资源访问
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
}
